package fhv.at.imageprocessing;

import java.awt.Rectangle;
import java.awt.image.renderable.ParameterBlock;
import java.io.Serializable;

import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import javax.media.jai.PlanarImage;

public class ImageProcessor implements Serializable {
	private static ImageProcessor m_instance;

	private ImageProcessor() {
	}

	public static ImageProcessor getInstance() {
		if (m_instance == null) {
			m_instance = new ImageProcessor();
		}
		return m_instance;
	}

	/**
	 * laden eines Bildes aus dem Filesystem
	 * 
	 * @param imagePath
	 * @return
	 */
	public PlanarImage loadImage(String imagePath) {
		return JAI.create("fileload", imagePath);
	}

	/***
	 * speichern eines Bildes in das Filesystem
	 * 
	 * @param image
	 * @param imagePath
	 * @param imageType
	 */
	public void saveImage(PlanarImage image, String imagePath, String imageType) {
		JAI.create("filestore", image, imagePath, imageType);
	}

	/**
	 * leifert einen Ausschnitt aus einem Bild
	 * 
	 * @param image
	 * @param rectangle
	 * @return
	 */
	public PlanarImage getROI(PlanarImage image, Rectangle rectangle) {

		return PlanarImage.wrapRenderedImage(image.getAsBufferedImage(
				rectangle, image.getColorModel()));
	}

	/**
	 * Aublaehen eines Bildes
	 * 
	 * @param image
	 * @param kernelData
	 * @return
	 */
	public PlanarImage getDilate(PlanarImage image, KernelJAI kernelData) {
		ParameterBlock pbErode = new ParameterBlock();
		pbErode.addSource(image);
		pbErode.add(kernelData);
		return JAI.create("dilate", pbErode);
	}

	/**
	 * Errodieren ein Bild
	 * 
	 * @param image
	 * @param kernelData
	 * @return
	 */
	public PlanarImage getErode(PlanarImage image, KernelJAI kernelData) {
		ParameterBlock pbErode = new ParameterBlock();
		pbErode.addSource(image);
		pbErode.add(kernelData);
		return JAI.create("erode", pbErode);
	}

	/**
	 * Invertieren eines Bildes
	 * 
	 * @param image
	 * @return
	 */
	public PlanarImage getInvert(PlanarImage image) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		return JAI.create("invert", pb);
	}

	/**
	 * glaetten eines Bildes
	 * 
	 * @param image
	 * @return
	 */
	public PlanarImage getMedian(PlanarImage image) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		return JAI.create("medianfilter", pb);
	}

	/**
	 * Bild1 mit Bild2 ueberlagern
	 * 
	 * @param image1
	 * @param image2
	 * @return
	 */
	public PlanarImage getOverlay(PlanarImage image1, PlanarImage image2) {
		return JAI.create("overlay", image1, image2);
	}

	/**
	 * 
	 * @param image
	 * @param low
	 * @param high
	 * @param map
	 * @return
	 */
	public PlanarImage getThreshold(PlanarImage image, double[] low,
			double[] high, double[] map) {

		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(low);
		pb.add(high);
		pb.add(map);
		return JAI.create("threshold", pb);
	}

	/**
	 * Bild verschieben
	 * 
	 * @param image
	 * @param x
	 * @param y
	 * @return
	 */
	public PlanarImage getTranslate(PlanarImage image, float x, float y) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(x);
		pb.add(y);
		pb.add(new InterpolationNearest());
		return JAI.create("translate", pb);
	}

	/**
	 * logischen anden
	 * 
	 * @param image1
	 * @param image2
	 * @return
	 */
	public PlanarImage getAND(PlanarImage image1, PlanarImage image2) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image1);
		pb.addSource(image2);
		return JAI.create("and", pb);
	}

	/**
	 * logisches oren
	 * 
	 * @param image1
	 * @param image2
	 * @return
	 */
	public PlanarImage getOR(PlanarImage image1, PlanarImage image2) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image1);
		pb.addSource(image2);
		return JAI.create("or", pb);
	}

	/**
	 * logisches noten
	 * 
	 * @param image1
	 * @param image2
	 * @return
	 */
	public PlanarImage getNOT(PlanarImage image1, PlanarImage image2) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image1);
		pb.addSource(image2);
		return JAI.create("not", pb);
	}

	/**
	 * logisches xoren
	 * 
	 * @param image1
	 * @param image2
	 * @return
	 */
	public PlanarImage getXOR(PlanarImage image1, PlanarImage image2) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image1);
		pb.addSource(image2);
		return JAI.create("xor", pb);
	}

	/***
	 * Kantenfindung horizontal
	 * 
	 * @param image
	 * @return
	 */
	public PlanarImage getSobelH(PlanarImage image) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(KernelJAI.GRADIENT_MASK_SOBEL_HORIZONTAL);
		return JAI.create("gradientmagnitude", pb);
	}

	/***
	 * Kantenfindung vertikal
	 * 
	 * @param image
	 * @return
	 */
	public PlanarImage getSobelV(PlanarImage image) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(KernelJAI.GRADIENT_MASK_SOBEL_VERTICAL);
		return JAI.create("gradientmagnitude", pb);
	}

	/***
	 * Kantenfindung horizontal und vertikal
	 * 
	 * @param image
	 * @return
	 */
	public PlanarImage getSobel(PlanarImage image, KernelJAI kernel) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(kernel);
		return JAI.create("gradientmagnitude", pb);
	}

	/***
	 * Laplace
	 * 
	 * @param image
	 * @param kernel
	 * @return
	 */
	public PlanarImage getLaplace(PlanarImage image, KernelJAI kernel) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(kernel);
		return JAI.create("convolve", pb);
	}

}
